﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace CircuitBreaker
{
    public class HalfOpenState : CircuitBreakerState
    {
        private readonly object _syncRoot = new object();
        private bool _entered = false;
        public HalfOpenState(CircuitBreaker circuitBreaker) : base(circuitBreaker) { }

        public override void ProtectedCodeIsAboutToBeCalled()
        {
            base.ProtectedCodeIsAboutToBeCalled();
            //just let 1 in
            if (!_entered)
            {
                if (Monitor.TryEnter(_syncRoot))
                {
                    try
                    {
                        if (!_entered)
                        {
                            _entered = true;
                        }
                        else
                        {
                            throw new OpenCircuitException();
                        }
                    }
                    finally
                    {
                        Monitor.Exit(_syncRoot);
                    }
                }
                else
                {
                    throw new OpenCircuitException();
                }
            }
            else
            {
                throw new OpenCircuitException();
            }
        }

        public override int ActUponException(Exception e)
        {
#if DEBUG
            Console.ForegroundColor = ConsoleColor.Magenta;
            Console.WriteLine(_circuitBreaker.Name + ": failed in half-open");
            Console.ForegroundColor = ConsoleColor.Gray;
#endif
            int failures = base.ActUponException(e);
            _circuitBreaker.Open();
            return failures;
        }

        public override void ProtectedCodeHasBeenCalled()
        {

            base.ProtectedCodeHasBeenCalled();
//#if DEBUG
//            Thread.Sleep(500);
//#endif
#if DEBUG
            Console.ForegroundColor = ConsoleColor.DarkCyan;
            Console.WriteLine(_circuitBreaker.Name + ": success in half-open");
            Console.ForegroundColor = ConsoleColor.Gray;
#endif
            _circuitBreaker.Close();
        }
    }
}